描述 通过fastjson反序列化某javabean时失败,并抛出以下异常:
1 2 Could not deserialize: autoType is not support. com.xxx.Shop; nested exception is com.alibaba.fastjson.JSONException: autoType is not support. com.xxx.Shop at com.alibaba.fastjson.support.spring.GenericFastJsonRedisSerializer.deserialize(GenericFastJsonRedisSerializer.java:37)
然而只有项目第一次反序列化该javabean时会抛异常失败,复现方式只有重启项目后的第一次反序列化操作。
过程 查询官方文档,开启AutoType的方法enable_autotype 。
但是文档中的方法均测试无效,无奈debug源码,发现抛出异常的代码为com.alibaba.fastjson.parser.ParserConfig
的1125行代码:
1 2 3 4 JavaBeanInfo beanInfo = JavaBeanInfo.build(clazz, clazz, propertyNamingStrategy); if (beanInfo.creatorConstructor != null && autoTypeSupport) { throw new JSONException("autoType is not support. " + typeName); }
经与正常反序列化的javabean比较后,发现反序列化失败的javabean在如上代码执行时,beanInfo.creatorConstructor
的值不为null,最后抛出autoType is not support
的异常。
继续追踪,在com.alibaba.fastjson.util.JavaBeanInfo
283行代码判断反序列化失败的javabean为接口或抽象类:
1 boolean isInterfaceOrAbstract = clazz.isInterface() || Modifier.isAbstract(clazz.getModifiers());
再于com.alibaba.fastjson.util.JavaBeanInfo
381行代码的if判断分支下给beanInfo.creatorConstructor
赋值:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 else if (!isInterfaceOrAbstract){ ... for (Constructor constructor : constructors) { Class<?>[] parameterTypes = constructor.getParameterTypes(); if (className.equals("org.springframework.security.web.authentication.WebAuthenticationDetails")) { if (parameterTypes.length == 2 && parameterTypes[0] == String.class && parameterTypes[1] == String.class) { creatorConstructor = constructor; creatorConstructor.setAccessible(true); paramNames = ASMUtils.lookupParameterNames(constructor); break; } } if (className.equals("org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken")) { if (parameterTypes.length == 3 && parameterTypes[0] == Object.class && parameterTypes[1] == Object.class && parameterTypes[2] == Collection.class) { creatorConstructor = constructor; creatorConstructor.setAccessible(true); paramNames = new String[] {"principal", "credentials", "authorities"}; break; } } if (className.equals("org.springframework.security.core.authority.SimpleGrantedAuthority")) { if (parameterTypes.length == 1 && parameterTypes[0] == String.class) { creatorConstructor = constructor; paramNames = new String[] {"authority"}; break; } } boolean is_public = (constructor.getModifiers() & Modifier.PUBLIC) != 0; if (!is_public) { continue; } String[] lookupParameterNames = ASMUtils.lookupParameterNames(constructor); if (lookupParameterNames == null || lookupParameterNames.length == 0) { continue; } if (creatorConstructor != null && paramNames != null && lookupParameterNames.length <= paramNames.length) { continue; } paramNames = lookupParameterNames; // 有参数构造方法给beanInfo.creatorConstructor赋值 creatorConstructor = constructor; } }
最终定位项目中通过fastjson反序列化失败,是因为该javabean没有无参构造方法,被fastjson判断为接口或抽象类,最终抛出autoType is not support
的异常。
解决 给javabean添加无参构造方法。